/*
 * Copyright [vega-ai-sdk] [rightbrain.art]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * According to vega feature, we modify some class，comment, field name, etc.
 */

package com.rightbrain.vegaai.tool.sdk.service;


import com.alibaba.fastjson.JSONObject;
import com.rightbrain.vegaai.tool.sdk.common.Resource;
import com.rightbrain.vegaai.tool.sdk.config.VegaConfig;
import com.rightbrain.vegaai.tool.sdk.exception.VegaAIException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class VegaHttpService {

    @Autowired
    private CloseableHttpClient vegaHttpClient;

    @Autowired
    private RequestConfig vegaRequestConfig;

    @Autowired
    private VegaConfig vegaConfig;

    /**
     * 发送httpGet请求
     *
     * @param url
     * @return
     */
    public Resource doGet(String url, String path) throws IOException, VegaAIException {
        Resource resource = null;
        HttpGet httpGet = new HttpGet(vegaConfig.getUrl() + url + path);
        long l = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        httpGet.setHeader("timestamp", String.valueOf(l));
        httpGet.setHeader("appKey", vegaConfig.getAppKey());
        httpGet.setHeader("version", "1.0.0");
        httpGet.setHeader("sign", signApiV1(l, url));
        httpGet.setHeader("openId", vegaConfig.getOpenId());
        httpGet.setConfig(vegaRequestConfig);
        CloseableHttpResponse response = null;
        response = vegaHttpClient.execute(httpGet);
        if (response.getStatusLine().getStatusCode() == 200) {
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            resource = JSONObject.parseObject(result, Resource.class);
            log.info("get response from vega {}", result);
        } else {
            log.error("get response error , error info is {}", JSONObject.toJSONString(response));
            throw new VegaAIException("获取异常");
        }
        try {
            response.close();
        } catch (IOException e) {
            log.error("fail to close http connection");
            e.printStackTrace();
        }
        return resource;
    }


    /**
     * 发送httpPost请求
     *
     * @return
     */
    public Resource doPost(String url, Map<String, Object> paramMap) throws IOException, VegaAIException {
        Resource resource = null;
        HttpPost httpPost = new HttpPost(vegaConfig.getUrl() + url);
        List<NameValuePair> paramList = new ArrayList<>();
        if (paramMap == null) {//抛出异常
            throw new VegaAIException("参数不允许为空");
        } else {
            Set<String> keySet = paramMap.keySet();
            NameValuePair pair = null;
            for (String key : keySet) {
                pair = new BasicNameValuePair(key, paramMap.get(key) == null ? "" : JSONObject.toJSONString(paramMap.get(key)));
                paramList.add(pair);
            }
        }
        long l = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        httpPost.setHeader("timestamp", String.valueOf(l));
        httpPost.setHeader("appKey", vegaConfig.getAppKey());
        httpPost.setHeader("version", "1.0.0");
        httpPost.setHeader("sign", signApiV1(l, url));
        httpPost.setHeader("openId", vegaConfig.getOpenId());
        httpPost.setConfig(vegaRequestConfig);
        UrlEncodedFormEntity entity = null;
        CloseableHttpResponse response = null;
        entity = new UrlEncodedFormEntity(paramList);
        httpPost.setEntity(entity);
        response = vegaHttpClient.execute(httpPost);
        if (response.getStatusLine().getStatusCode() == 200) {
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            resource = JSONObject.parseObject(result, Resource.class);
            log.info("get response from vega {}", result);
        } else {
            log.error("get response error , error info is {}", JSONObject.toJSONString(response));
            throw new VegaAIException("获取异常");
        }
        return resource;
    }

    //post请求参数为json格式
    public Resource doPostWithJson(String url, String json) throws IOException, VegaAIException {
        Resource resource = null;
        if (StringUtils.isEmpty(json)) {//抛出异常
            throw new VegaAIException("参数不允许为空");
        }
        HttpPost httpPost = new HttpPost(vegaConfig.getUrl() + url);
        long l = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        httpPost.setHeader("timestamp", String.valueOf(l));
        httpPost.setHeader("appKey", vegaConfig.getAppKey());
        httpPost.setHeader("version", "1.0.0");
        httpPost.setHeader("sign", signApiV1(l, url));
        httpPost.setHeader("openId", vegaConfig.getOpenId());
        httpPost.setConfig(vegaRequestConfig);
        CloseableHttpResponse response = null;
        try {
            //第三步：给httpPost设置JSON格式的参数
            StringEntity requestEntity = new StringEntity(json, "UTF-8");
            requestEntity.setContentEncoding("UTF-8");
            httpPost.setHeader("Content-type", "application/json");
            httpPost.setEntity(requestEntity);
            response = vegaHttpClient.execute(httpPost); //调接口获取返回值时，必须用此方法
            if (response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity(), "UTF-8");
                resource = JSONObject.parseObject(result, Resource.class);
                log.info("get response from vega {}", result);
            } else {
                log.error("get response error , error info is {}", JSONObject.toJSONString(response));
                throw new VegaAIException("获取异常");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resource;
    }

    private String signApiV1(long l, String path) {
        Map<String, String> map = new LinkedHashMap<>();
        log.info("signApiV1 here start to sigh api ,time is : {} , and the sign path is {}", l, path);
        map.put("timestamp", String.valueOf(l));  //值应该为毫秒数的字符串形式
        map.put("path", path);
        map.put("version", "1.0.0");
        List<String> storedKeys = Arrays.stream(map.keySet()
                        .toArray(new String[]{}))
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.toList());
        final String sign = storedKeys.stream()
                .map(key -> String.join("", key, map.get(key)))
                .collect(Collectors.joining()).trim()
                .concat(vegaConfig.getAppSecret());
        String finalSign = DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase();
        log.info("signApiV1 get finalSign : {}", finalSign);
        return finalSign;
    }
}
